package data;

import java.util.Random;

import myBot.distances;
import myBot.myBot;
import robocode.ScannedRobotEvent;

public class Generation {

	static int generationSize = 10;
	
	public data.MovementData generationpopulation[]=new data.MovementData[generationSize];
	public data.ShootingData generationshootingData[] = new data.ShootingData[generationSize];
	
	//movement operators
	public ArithmeticOperator velocityOperator;
	public ArithmeticOperator distanceToEnemyOperator;
	public ArithmeticOperator headingEnemyOperator;
	public ArithmeticOperator bearingOperator;
	public ArithmeticOperator robotFronDistanceToWallOperator;
	public ArithmeticOperator robotBackDistanceToWallOperator;
	public ArithmeticOperator robotRightDistanceToWallOperator;
	public ArithmeticOperator robotLeftDistanceToWallOperator;
	
	
	public Generation()
	{
		this.GenerateOperators();
		this.CreateGeneration();
	}
	
	
	public void CreateGeneration(){
		for(int i=0;i<generationSize ;i++){
			this.generationpopulation[i] = new MovementData();
			this.generationshootingData[i] = new ShootingData();
		}
	}
	
	public double Evaluator(RobotData Individual,ScannedRobotEvent e, myBot r)
	{
		double heading=r.getHeading();
		double frontdistance;
		double leftdistance;
		double rightdistance;
		double backdistance;
		double height=r.getBattleFieldHeight();
		double width=r.getBattleFieldWidth();
		double posX=r.getX();
		double posY=r.getY();
		double output=0;

		frontdistance=distances.distanceToWall(heading,height,width,posX,posY);
		rightdistance=distances.distanceToWall(heading+Math.PI/2,height,width,posX,posY);
		backdistance=distances.distanceToWall(heading+Math.PI,height,width,posX,posY);
		leftdistance=distances.distanceToWall(heading+Math.PI*(3/4),height,width,posX,posY);


		output=Individual.velocity*r.getVelocity()/8;
		
		output = ArithmeticOperators.Evaluate(output, Individual.bearing*e.getBearingRadians()/Math.PI, this.bearingOperator);
		output = ArithmeticOperators.Evaluate(output, Individual.distanceToEnemy*distances.intervall(e.getDistance(), 500), this.distanceToEnemyOperator);
		output = ArithmeticOperators.Evaluate(output, Individual.headingEnemy*Math.sin(e.getHeading()-heading), this.headingEnemyOperator);
		output = ArithmeticOperators.Evaluate(output, Individual.robotBackDistanceToWall*distances.intervall(backdistance, 200), this.robotBackDistanceToWallOperator);
		output = ArithmeticOperators.Evaluate(output, Individual.robotBackDistanceToWall*distances.intervall(frontdistance, 200), this.robotFronDistanceToWallOperator);
		output = ArithmeticOperators.Evaluate(output, Individual.robotBackDistanceToWall*distances.intervall(leftdistance, 200), this.robotLeftDistanceToWallOperator);
		output = ArithmeticOperators.Evaluate(output, Individual.robotBackDistanceToWall*distances.intervall(rightdistance, 200), this.robotRightDistanceToWallOperator);

		
		return ((1/(1+Math.exp(-output)))*2)-1;
	}
	
	public double ShootingEvaluator(RobotShootingData dat, ScannedRobotEvent e, myBot r)
	{
		double output = dat.enemyDistance*distances.intervall(e.getDistance(), 500);
		output += dat.enemyEnergy*e.getEnergy()/100;
		output += dat.enemyHeading*Math.sin(e.getHeading()-r.getHeading());
		output += dat.enemyVelocity*e.getVelocity()/8;
		output += dat.gunHeading*Math.sin(r.getGunHeading()-e.getHeading()); //?????????????
		output += dat.meEnergy*r.getEnergy()/100;
		
		return ((1/(1+Math.exp(-output)))*2)-1;
	}

	
	private void GenerateOperators()
	{
		Random r = new Random();
		this.bearingOperator = GetOperator((r.nextInt() % 4));
		this.distanceToEnemyOperator = GetOperator((r.nextInt() % 4));
		this.headingEnemyOperator = GetOperator((r.nextInt() % 4));
		this.velocityOperator = GetOperator((r.nextInt() % 4));
		this.robotBackDistanceToWallOperator = GetOperator((r.nextInt() % 4));
		this.robotFronDistanceToWallOperator = GetOperator((r.nextInt() % 4));
		this.robotLeftDistanceToWallOperator = GetOperator((r.nextInt() % 4));
		this.robotRightDistanceToWallOperator = GetOperator((r.nextInt() % 4));
		
	}
	
	private static ArithmeticOperator GetOperator(int i)
	{
		//return (i % 2 == 0) ? ArithmeticOperator.Addition : ArithmeticOperator.Subtraction; 
		return ArithmeticOperator.Addition;
		
	/*	switch(i)
		{
		case 0:
			return ArithmeticOperator.Addition;
		case 1:
			return ArithmeticOperator.Subtraction;
		case 2:
			return ArithmeticOperator.Multiplication;
		case 3:
			return ArithmeticOperator.Division;
		}
		
		return ArithmeticOperator.Unknown;*/
	}
}
